"""
urllib.request.urlopen() 不能封装 headers(请求头)访问服务器
urllib.request.Request() 能够封装 headers(请求头)访问服务器

Handler处理器：
在访问 Web服务器时，由于 request 对象不能携带 Cookie 和 代理IP，为了实现更多的扩展功能，引用了 Handler 处理器。
通过两种不同对象创建的 handler 对象拥有 携带 Cookie 和 代理IP 的功能，使通过它创建的 opener 这个伪浏览器也有相应功能。

步骤：
1、创建 Handler 对象，handler = urllib.request.HTTPHandler()
2、然后作为 urllib.request.build_opener() 的参数创建 opener 对象
3、使用 Request 对象封装url 和 headers 创建 request 对象
4、使用 opener.open() 发送请求
5、使用 collections 包中的 namedtuple 来创建新的响应对象，这个响应对象可以拥有 opener.open() 响应对象的属性
"""

from urllib.request import HTTPHandler, build_opener, Request
from collections import namedtuple

headers = {
	'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 S\
	afari/537.36',
	'Host': 'www.baidu.com'
}

# 创建类
# namedtuple 命名元组，可以定义新的响应对象，这个响应对象可以拥有自定义属性，相当于扩展
# 以下表示新创建的 Response 响应对象属于 Response 类型，它拥有后面的自定义属性
Response = namedtuple('Response', field_names=['headers', 'code', 'body', 'text', 'encoding'])


def get(url):
	# 创建 handler 对象
	# HTTPHandler 用于处理 http 请求协议
	handler = HTTPHandler()

	# 将 handler 对象作为 build_opener() 的参数传入
	opener = build_opener(handler)

	# # 创建 request 对象
	# req = Request(url, headers=headers)

	# 发送请求，服务器返回响应对象 resp
	# resp = opener.open(req)
	resp = opener.open(url)

	# 读取响应数据用 read()，结果为 字节，可以使用 decode('utf-8')解码
	# # 读取响应数据
	# # 读取的数据为二进制，所以需要转码
	# resp_data = resp.read()
	# print(type(resp_data))  # byte
	# return resp_data.decode('utf-8')

	# 为新创建的 Response 对象添加响应头
	# resp.getheaders()：获取返回响应对象的响应头，然后将其 字典化 并添加给 自定义的 Response 对象
	headers = dict(resp.getheaders())

	try:
		# 获取响应头中的编码格式
		# 响应头中的编码格式常见有：text/html | image/png;charset=utf-8
		# 获取 utf-8 编码格式，对响应头进行切片操作，取最后一个元素
		encoding = headers['Content-Type'].split('=')[-1]
	except:
		encoding = 'utf-8'

	code = resp.code

	body = resp.read()

	# 对 body 进行解码 形成文本
	text = body.decode(encoding)

	# 为新创建的 Response 对象添加 resp 响应对象的部分属性
	return Response(headers=headers, encoding=encoding, code=code, body=body, text=text)


if __name__ == '__main__':
	# print(get('http://www.baidu.com'))
	# 指定变量 resp 的数据类型为 Response,所以拥有与 Response 一样的属性,可以调用
	resp: Response = get('http://www.baidu.com')
	print(resp.code)
	print(resp.text)
	print(resp.encoding)
